package com.zp95sky.demo.aidemo.biz.impl;

import cn.hutool.core.lang.Snowflake;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zp95sky.demo.aidemo.biz.TextProcessingBiz;
import com.zp95sky.demo.aidemo.common.constant.ResponseCodeConstant;
import com.zp95sky.demo.aidemo.common.enums.HandleResultEnum;
import com.zp95sky.demo.aidemo.common.exception.CustomException;
import com.zp95sky.demo.aidemo.common.response.BaseResponse;
import com.zp95sky.demo.aidemo.common.utils.ResponseUtil;
import com.zp95sky.demo.aidemo.domain.KeyWordInfoDo;
import com.zp95sky.demo.aidemo.domain.ProcessTextResultDo;
import com.zp95sky.demo.aidemo.dto.ParagraphInfoDto;
import com.zp95sky.demo.aidemo.dto.ProcessTextAsyncDto;
import com.zp95sky.demo.aidemo.dto.TextResultQueryDto;
import com.zp95sky.demo.aidemo.entity.AiTaskHandleRecord;
import com.zp95sky.demo.aidemo.service.AiTaskHandleRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class TextProcessingBizImpl implements TextProcessingBiz {

    private final AiTaskHandleRecordService aiTaskHandleRecordService;

    private final DeepSeekChatModel chatModel;
    private final ResponseUtil responseUtil;
    private final Snowflake snowflake;
    private final ObjectMapper objectMapper;

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10000), (r, executor) -> log.error("Im task queue over 10000!"));

    private static final String PROMPT = """
            ### 角色定义
            
            你是一名专业的政企会议记录解析助手，具备以下能力：
            
            - 能够从政企类会议对话记录中提取核心信息
            - 严格遵循会议原文内容，杜绝主观臆断与内容创造
            - 输出符合政企公文规范的结构化数据，格式需便于代码解析
            
            ### 任务描述
            
            请根据提供的政企会议对话记录，完成以下信息提取任务：
            
            1. 归纳会议核心内容形成会议纪要
            2. 梳理待执行任务形成待办清单
            3. 提炼 3-5 个核心术语作为会议关键词
            
            ### 处理要求
            
            * 内容约束：所有输出信息必须完全源自对话记录原文，严禁添加任何未提及的内容
            * 语言风格：采用正式、严肃的政企公文用语，避免口语化表达
            * 会议关键词要求：必须出自会议内容原文
            * 空值处理：若某类信息无法从记录中提取，对应字段只返回前缀后缀即可，中间内容禁止自行发挥，比如 会议待办_start@@@@@@会议待办_end
            * 格式规范：使用指定符号分隔字段
            
            ### 输出格式
            
            会议纪要_start@@@会议纪要内容1：：：会议纪要内容2@@@会议纪要_end
            会议待办_start@@@待办事项1：：：待办事项2@@@会议待办_end
            会议关键词_start@@@关键词1：：：关键词2：：：关键词3@@@会议关键词_end
            
            ### 格式细则说明
            
            每个模块以 会议纪要_start@@@ 开头，@@@会议纪要_end 结尾，多项内容用 ：：： 分隔
            针对输入内容中的多条记录，直接输出大模型生成的内容，记录前禁止添加任何内容说明。
            比如直接输出 会议纪要_start@@@会议纪要内容1：：：会议纪要内容2@@@会议纪要_end，禁止输出 会议纪要_start@@@会议内容1：会议纪要内容1：：：会议内容2：会议纪要内容2@@@会议纪要_end
            """;
    
    @Override
    public BaseResponse<String> processTextAsync(ProcessTextAsyncDto asyncDto) {
        // 参数校验
        if (ObjectUtils.isEmpty(asyncDto) || ObjectUtils.isEmpty(asyncDto.getPs())) {
            log.error("Invalid input parameters: asyncDto={}", asyncDto);
            throw new CustomException(ResponseCodeConstant.BAD_REQUEST_CODE);
        }

        // 生成任务ID
        long taskId = snowflake.nextId();

        // 记录任务
        AiTaskHandleRecord record = AiTaskHandleRecord.builder()
                .id(taskId).appKey("")
                .aiResult(HandleResultEnum.PROCESSING.getValue()).createTime(LocalDateTime.now()).build();
        aiTaskHandleRecordService.save(record);

        // 异步处理
        threadPoolExecutor.execute(() -> aiHandleText(taskId, asyncDto));

        // 返回任务ID
        return responseUtil.buildSuccessResponse(String.valueOf(taskId));
    }

    @Override
    public BaseResponse<ProcessTextResultDo> textResultQuery(TextResultQueryDto queryDto) throws JsonProcessingException {
        if (ObjectUtils.isEmpty(queryDto.getTaskId())) {
            log.error("Invalid input parameters: asyncDto={}", queryDto);
            throw new CustomException(ResponseCodeConstant.BAD_REQUEST_CODE);
        }

        AiTaskHandleRecord record = aiTaskHandleRecordService.getById(queryDto.getTaskId());
        if (HandleResultEnum.PROCESSING.getValue().equals(record.getAiResult())) {
            throw new CustomException(ResponseCodeConstant.AI_HANDLE_PROCESSING_CODE);
        }

        if (HandleResultEnum.FAIL.getValue().equals(record.getAiResult())) {
            throw new CustomException(ResponseCodeConstant.AI_HANDLE_FAIL_CODE);
        }

        ProcessTextResultDo resultDo = objectMapper.readValue(record.getFinalResult(), ProcessTextResultDo.class);
        return responseUtil.buildSuccessResponse(resultDo);
    }

    private void aiHandleText(long taskId, ProcessTextAsyncDto asyncDto) {
        // 构建用户消息
        String userMessageStr = asyncDto.getPs().stream()
                .map(ParagraphInfoDto::getWs)
                .collect(Collectors.joining("\n"));

        AiTaskHandleRecord taskHandleRecord = AiTaskHandleRecord.builder()
                .id(taskId).userMessage(userMessageStr)
                .systemMessage(PROMPT)
                .build();

        try {
            // 构建AI请求
            Message systemMessage = new SystemMessage(PROMPT);
            UserMessage userMessage = new UserMessage(userMessageStr);
            Prompt prompt = new Prompt(userMessage, systemMessage);

            // 调用AI服务
            log.info("Calling AI service with prompt length: {}", userMessageStr.length());
            ChatResponse response = chatModel.call(prompt);

            // 验证AI响应
            if (response == null || response.getResult() == null ||
                    response.getResult().getOutput() == null ||
                    response.getResult().getOutput().getText() == null) {
                log.error("Invalid AI response: {}", response);
                // 更新处理结果
                taskHandleRecord.setAiResult(HandleResultEnum.FAIL.getValue());
                aiTaskHandleRecordService.updateById(taskHandleRecord);
                throw new CustomException(ResponseCodeConstant.AI_HANDLE_ERROR_CODE);
            }

            String aiResponse = response.getResult().getOutput().getText();
            log.info("AI response received, length: {}", aiResponse.length());

            // 解析会议纪要
            List<String> summaryList = parseSection(aiResponse, "会议纪要_start@@@", "@@@会议纪要_end");
            // 解析待办事项
            List<String> todoList = parseSection(aiResponse, "会议待办_start@@@", "@@@会议待办_end");
            // 解析关键词
            List<String> keywordList = parseSection(aiResponse, "会议关键词_start@@@", "@@@会议关键词_end");

            ProcessTextResultDo resultDo = ProcessTextResultDo.builder().build();
            resultDo.setTaskStatus(HandleResultEnum.SUCCESS.getValue());

            if (!CollectionUtils.isEmpty(summaryList)) {
                resultDo.setTextSummaryInfos(summaryList);
            }
            if (!CollectionUtils.isEmpty(todoList)) {
                resultDo.setTodoInfos(todoList);
            }
            if (!CollectionUtils.isEmpty(keywordList)) {
                resultDo.setKeyWordInfoDos(keywordList.stream().map(this::buildKeyWordInfoDo).toList());
            }

            // 更新任务信息
            taskHandleRecord.setAiResult(HandleResultEnum.SUCCESS.getValue());
            taskHandleRecord.setAiResponse(aiResponse);
            taskHandleRecord.setFinalResult(objectMapper.writeValueAsString(resultDo));
            aiTaskHandleRecordService.updateById(taskHandleRecord);
        } catch (Exception e) {
            log.error("Error processing text async", e);
            taskHandleRecord.setAiResult(HandleResultEnum.FAIL.getValue());
            aiTaskHandleRecordService.updateById(taskHandleRecord);
            throw new CustomException(ResponseCodeConstant.INTERNAL_SERVER_ERROR_CODE);
        }
    }

    private KeyWordInfoDo buildKeyWordInfoDo(String word) {
        return KeyWordInfoDo.builder()
                .word(word)
                .build();
    }

    /**
     * 解析特定部分的内容为列表
     * @param content 完整内容
     * @param startTag 开始标记
     * @param endTag 结束标记
     * @return 解析后的列表
     */
    private List<String> parseSection(String content, String startTag, String endTag) {
        try {
            int startIndex = content.indexOf(startTag);
            int endIndex = content.indexOf(endTag);

            if (startIndex == -1 || endIndex == -1 || startIndex >= endIndex) {
                log.warn("Section not found or invalid format: startTag={}, endTag={}", startTag, endTag);
                return Collections.emptyList();
            }

            String sectionContent = content.substring(startIndex + startTag.length(), endIndex);
            if (ObjectUtils.isEmpty(sectionContent)) {
                return Collections.emptyList();
            }

            return Arrays.asList(sectionContent.split("：：："));
        } catch (Exception e) {
            log.error("Error parsing section: startTag={}, endTag={}", startTag, endTag, e);
            return Collections.emptyList();
        }
    }
}